/**
 * Copyright (C) 2010-2016 eBusiness Information, Excilys Group
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed To in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ohosannotations.logger;

import org.ohosannotations.OhosAnnotationsEnvironment;
import org.ohosannotations.Option;
import org.ohosannotations.logger.appender.Appender;
import org.ohosannotations.logger.appender.ConsoleAppender;
import org.ohosannotations.logger.appender.FileAppender;
import org.ohosannotations.logger.appender.MessagerAppender;
import org.ohosannotations.logger.formatter.Formatter;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;

/**
 * 记录器上下文
 *
 * @author dev
 * @since 2021-07-22
 */
public final class LoggerContext {
    /**
     * 选择日志级别
     */
    public static final Option OPTION_LOG_LEVEL = new Option("logLevel", "WARN");
    /**
     * 选择日志appender控制台
     */
    public static final Option OPTION_LOG_APPENDER_CONSOLE = new Option("logAppenderConsole", "false");
    /**
     * 选择日志appender文件
     */
    public static final Option OPTION_LOG_APPENDER_FILE = new Option("logAppenderFile", "true");
    private static final Level DEFAULT_LEVEL = Level.WARN;
    private static volatile LoggerContext instance = null;
    private Level currentLevel = DEFAULT_LEVEL;
    private List<Appender> appenders = new ArrayList<>();

    /**
     * 记录器上下文
     */
    private LoggerContext() {
    }

    /**
     * 获得实例
     *
     * @return {@link LoggerContext}
     */
    public static LoggerContext getInstance() {
        if (instance == null) {
            synchronized (LoggerContext.class) {
                if (instance == null) {
                    instance = new LoggerContext();
                }
            }
        }
        return instance;
    }

    /**
     * 写日志
     *
     * @param level 水平
     * @param loggerName 日志的名字
     * @param message 消息
     * @param element 元素
     * @param annotationMirror 注释的镜子
     * @param thr 用力推
     * @param args arg游戏
     */
    public void writeLog(Level level, String loggerName, String message,
        Element element, AnnotationMirror annotationMirror, Throwable thr, Object... args) {
        for (Appender appender : appenders) {
            Formatter formatter = appender.getFormatter();
            String log = formatter.buildLog(level, loggerName, message, thr, args);
            appender.append(level, element, annotationMirror, log);
        }
    }

    /**
     * 得到当前水平
     *
     * @return {@link Level}
     */
    public Level getCurrentLevel() {
        return currentLevel;
    }

    /**
     * 设置当前水平
     *
     * @param currentLevel 当前水平
     */
    public void setCurrentLevel(Level currentLevel) {
        this.currentLevel = currentLevel;
    }

    /**
     * 设置环境
     *
     * @param environment 环境
     */
    public void setEnvironment(OhosAnnotationsEnvironment environment) {
        appenders.clear();
        resolveLogLevel(environment);
        addConsoleAppender(environment);
        addFileAppender(environment);
        appenders.add(new MessagerAppender());

        for (Appender appender : appenders) {
            appender.setEnvironment(environment);
            appender.open();
        }
    }

    /**
     * 关闭
     *
     * @param lastRound 最后一轮
     */
    public void close(boolean lastRound) {
        for (Appender appender : appenders) {
            appender.close(lastRound);
        }
    }

    /**
     * 解决日志级别
     *
     * @param environment 环境
     */
    private void resolveLogLevel(OhosAnnotationsEnvironment environment) {
        Level level = Level.WARN;
        try {
            level = Level.parse(environment.getOptionValue(OPTION_LOG_LEVEL));
        } catch (Exception ignored) {
            // Do nothing, keep the default value;
        }
        setCurrentLevel(level);
    }

    /**
     * 添加控制台appender
     *
     * @param environment 环境
     */
    private void addConsoleAppender(OhosAnnotationsEnvironment environment) {
        if (environment.getOptionBooleanValue(OPTION_LOG_APPENDER_CONSOLE)) {
            appenders.add(new ConsoleAppender());
        }
    }

    /**
     * 添加文件appender
     *
     * @param environment 环境
     */
    private void addFileAppender(OhosAnnotationsEnvironment environment) {
        if (environment.getOptionBooleanValue(OPTION_LOG_APPENDER_FILE)) {
            appenders.add(new FileAppender());
        }
    }
}
